const std = @import("std");

pub const Backend = enum {
    no_backend,
    // glfw_wgpu,
    glfw_opengl3,
    glfw_vulkan,
    glfw_dx12,
    win32_dx12,
    glfw,
    // sdl2_opengl3,
    osx_metal,
    // sdl2,
    // sdl2_renderer,
    // sdl3,
    // sdl3_opengl3,
    // sdl3_renderer,
    // sdl3_gpu,
};

pub fn build(b: *std.Build) void {
    const optimize = b.standardOptimizeOption(.{});
    const target = b.standardTargetOptions(.{});

    const options = .{
        .backend = b.option(Backend, "backend", "Backend to build (default: no_backend)") orelse .no_backend,
        .shared = b.option(
            bool,
            "shared",
            "Bulid as a shared library",
        ) orelse false,
        .with_implot = b.option(
            bool,
            "with_implot",
            "Build with bundled implot source",
        ) orelse false,
        .with_gizmo = b.option(
            bool,
            "with_gizmo",
            "Build with bundled ImGuizmo tool",
        ) orelse false,
        .with_node_editor = b.option(
            bool,
            "with_node_editor",
            "Build with bundled ImGui node editor",
        ) orelse false,
        .with_te = b.option(
            bool,
            "with_te",
            "Build with bundled test engine support",
        ) orelse false,
        .with_freetype = b.option(
            bool,
            "with_freetype",
            "Build with system FreeType engine support",
        ) orelse false,
        .use_wchar32 = b.option(
            bool,
            "use_wchar32",
            "Extended unicode support",
        ) orelse false,
        .use_32bit_draw_idx = b.option(
            bool,
            "use_32bit_draw_idx",
            "Use 32-bit draw index",
        ) orelse false,
        .disable_thread_safety = b.option(
            bool,
            "disable_thread_safety",
            "Disable thread safety",
        ) orelse false,
    };

    const options_step = b.addOptions();
    inline for (std.meta.fields(@TypeOf(options))) |field| {
        options_step.addOption(field.type, field.name, @field(options, field.name));
    }

    const options_module = options_step.createModule();

    _ = b.addModule("root", .{
        .root_source_file = b.path("src/gui.zig"),
        .imports = &.{
            .{ .name = "zgui_options", .module = options_module },
        },
    });

    const cflags = &.{
        "-fno-sanitize=undefined",
        "-Wno-elaborated-enum-base",
        "-Wno-error=date-time",
        if (options.use_32bit_draw_idx) "-DIMGUI_USE_32BIT_DRAW_INDEX" else "",
    };

    const objcflags = &.{
        "-Wno-deprecated",
        "-Wno-pedantic",
        "-Wno-availability",
    };

    const imgui = if (options.shared) blk: {
        const lib = b.addLibrary(.{
            .linkage = .dynamic,
            .name = "imgui",
            .root_module = b.createModule(.{
                .target = target,
                .optimize = optimize,
            }),
            // .target = target,
            // .optimize = optimize,
        });

        if (target.result.os.tag == .windows) {
            lib.root_module.addCMacro("IMGUI_API", "__declspec(dllexport)");
            lib.root_module.addCMacro("IMPLOT_API", "__declspec(dllexport)");
            lib.root_module.addCMacro("ZGUI_API", "__declspec(dllexport)");
        }

        if (target.result.os.tag == .macos) {
            lib.linker_allow_shlib_undefined = true;
        }

        break :blk lib;
    } else b.addLibrary(.{
        .linkage = .static,
        .name = "imgui",
        .root_module = b.createModule(.{
            .target = target,
            .optimize = optimize,
        }),
        // .target = target,
        // .optimize = optimize,
    });

    b.installArtifact(imgui);

    // const emscripten = target.result.os.tag == .emscripten;

    imgui.addIncludePath(b.path("libs"));
    imgui.addIncludePath(b.path("libs/imgui"));

    imgui.linkLibC();

    imgui.linkLibCpp();
    imgui.linkSystemLibrary("c");
    // imgui.root_module.override_link_option(
    //     .{ .emit = imgui.getEmittedBin() },
    //     "-sASSERTIONS",
    // );
    // if (target.result.abi != .msvc)
    //     imgui.linkLibCpp();

    imgui.addCSourceFile(.{
        .file = b.path("src/zgui.cpp"),
        .flags = cflags,
    });

    imgui.addCSourceFiles(.{
        .files = &.{
            "libs/imgui/imgui.cpp",
            "libs/imgui/imgui_widgets.cpp",
            "libs/imgui/imgui_tables.cpp",
            "libs/imgui/imgui_draw.cpp",
            "libs/imgui/imgui_demo.cpp",
        },
        .flags = cflags,
    });

    if (options.with_freetype) {
        if (b.lazyDependency("freetype", .{})) |freetype| {
            imgui.linkLibrary(freetype.artifact("freetype"));
        }
        imgui.addCSourceFile(.{
            .file = b.path("libs/imgui/misc/freetype/imgui_freetype.cpp"),
            .flags = cflags,
        });
        imgui.root_module.addCMacro("IMGUI_ENABLE_FREETYPE", "1");
    }

    if (options.use_wchar32) {
        imgui.root_module.addCMacro("IMGUI_USE_WCHAR32", "1");
    }

    if (options.with_implot) {
        imgui.addIncludePath(b.path("libs/implot"));

        imgui.addCSourceFile(.{
            .file = b.path("src/zplot.cpp"),
            .flags = cflags,
        });

        imgui.addCSourceFiles(.{
            .files = &.{
                "libs/implot/implot_demo.cpp",
                "libs/implot/implot.cpp",
                "libs/implot/implot_items.cpp",
            },
            .flags = cflags,
        });
    }

    if (options.with_gizmo) {
        imgui.addIncludePath(b.path("libs/imguizmo/"));

        imgui.addCSourceFile(.{
            .file = b.path("src/zgizmo.cpp"),
            .flags = cflags,
        });

        imgui.addCSourceFiles(.{
            .files = &.{
                "libs/imguizmo/ImGuizmo.cpp",
            },
            .flags = cflags,
        });
    }

    if (options.with_node_editor) {
        imgui.addCSourceFile(.{
            .file = b.path("src/znode_editor.cpp"),
            .flags = cflags,
        });

        imgui.addCSourceFile(.{ .file = b.path("libs/node_editor/crude_json.cpp"), .flags = cflags });
        imgui.addCSourceFile(.{ .file = b.path("libs/node_editor/imgui_canvas.cpp"), .flags = cflags });
        imgui.addCSourceFile(.{ .file = b.path("libs/node_editor/imgui_node_editor_api.cpp"), .flags = cflags });
        imgui.addCSourceFile(.{ .file = b.path("libs/node_editor/imgui_node_editor.cpp"), .flags = cflags });
    }

    if (options.with_te) {
        imgui.addCSourceFile(.{
            .file = b.path("src/zte.cpp"),
            .flags = cflags,
        });

        imgui.root_module.addCMacro("IMGUI_ENABLE_TEST_ENGINE", "");
        imgui.root_module.addCMacro("IMGUI_TEST_ENGINE_ENABLE_COROUTINE_STDTHREAD_IMPL", "1");

        imgui.addIncludePath(b.path("libs/imgui_test_engine/"));

        imgui.addCSourceFile(.{ .file = b.path("libs/imgui_test_engine/imgui_capture_tool.cpp"), .flags = cflags });
        imgui.addCSourceFile(.{ .file = b.path("libs/imgui_test_engine/imgui_te_context.cpp"), .flags = cflags });
        imgui.addCSourceFile(.{ .file = b.path("libs/imgui_test_engine/imgui_te_coroutine.cpp"), .flags = cflags });
        imgui.addCSourceFile(.{ .file = b.path("libs/imgui_test_engine/imgui_te_engine.cpp"), .flags = cflags });
        imgui.addCSourceFile(.{ .file = b.path("libs/imgui_test_engine/imgui_te_exporters.cpp"), .flags = cflags });
        imgui.addCSourceFile(.{ .file = b.path("libs/imgui_test_engine/imgui_te_perftool.cpp"), .flags = cflags });
        imgui.addCSourceFile(.{ .file = b.path("libs/imgui_test_engine/imgui_te_ui.cpp"), .flags = cflags });
        imgui.addCSourceFile(.{ .file = b.path("libs/imgui_test_engine/imgui_te_utils.cpp"), .flags = cflags });
    }

    switch (options.backend) {
        // .glfw_wgpu => {
        //     std.debug.print("need wpu***********************\n", .{});
        //     if (emscripten) {
        //         imgui.addSystemIncludePath(.{
        //             .cwd_relative = b.pathJoin(&.{ b.sysroot.?, "include" }),
        //         });
        //     } else {
        //         if (b.lazyDependency("zglfw", .{})) |zglfw| {
        //             imgui.addIncludePath(zglfw.path("libs/glfw/include"));
        //         }
        //         if (b.lazyDependency("zgpu", .{})) |zgpu| {
        //             imgui.addIncludePath(zgpu.path("libs/dawn/include"));
        //         }
        //     }
        //     imgui.addCSourceFiles(.{
        //         .files = &.{
        //             "libs/imgui/backends/imgui_impl_glfw.cpp",
        //             "libs/imgui/backends/imgui_impl_wgpu.cpp",
        //         },
        //         .flags = cflags,
        //     });
        // },
        .glfw_opengl3 => {
            if (b.lazyDependency("zglfw", .{})) |zglfw| {
                imgui.addIncludePath(zglfw.path("libs/glfw/include"));
            }
            imgui.addCSourceFiles(.{
                .files = &.{
                    "libs/imgui/backends/imgui_impl_glfw.cpp",
                    "libs/imgui/backends/imgui_impl_opengl3.cpp",
                },
                .flags = &(cflags.* ++ .{"-DIMGUI_IMPL_OPENGL_LOADER_CUSTOM"}),
            });
        },
        .glfw_dx12 => {
            if (b.lazyDependency("zglfw", .{})) |zglfw| {
                imgui.addIncludePath(zglfw.path("libs/glfw/include"));
            }
            imgui.addCSourceFiles(.{
                .files = &.{
                    "libs/imgui/backends/imgui_impl_glfw.cpp",
                    "libs/imgui/backends/imgui_impl_dx12.cpp",
                },
                .flags = cflags,
            });
            imgui.linkSystemLibrary("d3dcompiler_47");
        },
        .win32_dx12 => {
            imgui.addCSourceFiles(.{
                .files = &.{
                    "libs/imgui/backends/imgui_impl_win32.cpp",
                    "libs/imgui/backends/imgui_impl_dx12.cpp",
                },
                .flags = cflags,
            });
            imgui.linkSystemLibrary("d3dcompiler_47");
            imgui.linkSystemLibrary("dwmapi");
            switch (target.result.abi) {
                .msvc => imgui.linkSystemLibrary("Gdi32"),
                .gnu => imgui.linkSystemLibrary("gdi32"),
                else => {},
            }
        },
        .glfw_vulkan => {
            if (b.lazyDependency("zglfw", .{})) |zglfw| {
                imgui.addIncludePath(zglfw.path("libs/glfw/include"));
            }

            imgui.addCSourceFiles(.{
                .files = &.{
                    "libs/imgui/backends/imgui_impl_glfw.cpp",
                    "libs/imgui/backends/imgui_impl_vulkan.cpp",
                },
                .flags = &(cflags.* ++ .{ "-DVK_NO_PROTOTYPES", "-DZGUI_DEGAMMA" }),
            });
        },
        .glfw => {
            if (b.lazyDependency("zglfw", .{})) |zglfw| {
                imgui.addIncludePath(zglfw.path("libs/glfw/include"));
            }
            imgui.addCSourceFiles(.{
                .files = &.{
                    "libs/imgui/backends/imgui_impl_glfw.cpp",
                },
                .flags = cflags,
            });
        },
        // .sdl2_opengl3 => {
        //     if (b.lazyDependency("zsdl", .{})) |zsdl| {
        //         imgui.addIncludePath(zsdl.path("libs/sdl2/include"));
        //     }
        //     imgui.addCSourceFiles(.{
        //         .files = &.{
        //             "libs/imgui/backends/imgui_impl_opengl3_loader.h",
        //             "libs/imgui/backends/imgui_impl_sdl2.cpp",
        //             "libs/imgui/backends/imgui_impl_opengl3.cpp",
        //         },
        //         .flags = &(cflags.* ++ .{"-DIMGUI_IMPL_OPENGL_LOADER_IMGL3W"}),
        //     });
        // },
        .osx_metal => {
            imgui.linkFramework("Foundation");
            imgui.linkFramework("Metal");
            imgui.linkFramework("Cocoa");
            imgui.linkFramework("QuartzCore");
            imgui.addCSourceFiles(.{
                .files = &.{
                    "libs/imgui/backends/imgui_impl_osx.mm",
                    "libs/imgui/backends/imgui_impl_metal.mm",
                },
                .flags = objcflags,
            });
        },
        // .sdl2 => {
        //     if (b.lazyDependency("zsdl", .{})) |zsdl| {
        //         imgui.addIncludePath(zsdl.path("libs/sdl2/include"));
        //     }
        //     imgui.addCSourceFiles(.{
        //         .files = &.{
        //             "libs/imgui/backends/imgui_impl_sdl2.cpp",
        //         },
        //         .flags = cflags,
        //     });
        // },
        // .sdl2_renderer => {
        //     if (b.lazyDependency("zsdl", .{})) |zsdl| {
        //         imgui.addIncludePath(zsdl.path("libs/sdl2/include"));
        //     }
        //     imgui.addCSourceFiles(.{
        //         .files = &.{
        //             "libs/imgui/backends/imgui_impl_sdl2.cpp",
        //             "libs/imgui/backends/imgui_impl_sdlrenderer2.cpp",
        //         },
        //         .flags = cflags,
        //     });
        // },
        // .sdl3_gpu => {
        //     if (b.lazyDependency("zsdl", .{})) |zsdl| {
        //         imgui.addIncludePath(zsdl.path("libs/sdl3/include"));
        //     }
        //     imgui.addCSourceFiles(.{
        //         .files = &.{
        //             "libs/imgui/backends/imgui_impl_sdl3.cpp",
        //             "libs/imgui/backends/imgui_impl_sdlgpu3.cpp",
        //         },
        //         .flags = cflags,
        //     });
        // },
        // .sdl3_renderer => {
        //     if (b.lazyDependency("zsdl", .{})) |zsdl| {
        //         imgui.addIncludePath(zsdl.path("libs/sdl3/include"));
        //     }
        //     imgui.addCSourceFiles(.{
        //         .files = &.{
        //             "libs/imgui/backends/imgui_impl_sdl3.cpp",
        //             "libs/imgui/backends/imgui_impl_sdlrenderer3.cpp",
        //         },
        //         .flags = cflags,
        //     });
        // },
        // .sdl3_opengl3 => {
        //     if (b.lazyDependency("zsdl", .{})) |zsdl| {
        //         imgui.addIncludePath(zsdl.path("libs/sdl3/include/SDL3"));
        //     }
        //     imgui.addCSourceFiles(.{
        //         .files = &.{
        //             "libs/imgui/backends/imgui_impl_sdl3.cpp",
        //             "libs/imgui/backends/imgui_impl_opengl3.cpp",
        //         },
        //         .flags = &(cflags.* ++ .{"-DIMGUI_IMPL_OPENGL_LOADER_IMGL3W"}),
        //     });
        // },
        // .sdl3 => {
        //     if (b.lazyDependency("zsdl", .{})) |zsdl| {
        //         imgui.addIncludePath(zsdl.path("libs/sdl3/include"));
        //     }
        //     imgui.addCSourceFiles(.{
        //         .files = &.{
        //             "libs/imgui/backends/imgui_impl_sdl3.cpp",
        //         },
        //         .flags = cflags,
        //     });
        // },
        .no_backend => {},
    }

    if (target.result.os.tag == .macos) {
        if (b.lazyDependency("system_sdk", .{})) |system_sdk| {
            imgui.addSystemIncludePath(system_sdk.path("macos12/usr/include"));
            imgui.addFrameworkPath(system_sdk.path("macos12/System/Library/Frameworks"));
        }
    }

    const test_step = b.step("test", "Run zgui tests");

    const tests = b.addTest(.{
        .name = "zgui-tests",
        .root_module = b.createModule(.{
            .root_source_file = b.path("src/gui.zig"),
            .target = target,
            .optimize = optimize,
        }),
        // .root_source_file = b.path("src/gui.zig"),

    });
    b.installArtifact(tests);

    tests.root_module.addImport("zgui_options", options_module);
    tests.linkLibrary(imgui);

    test_step.dependOn(&b.addRunArtifact(tests).step);
    const build_imgui_bc = buildCpp(b, target, optimize, options);
    b.getInstallStep().dependOn(build_imgui_bc);

    std.debug.print("empp path:{s}\n", .{emppPath(b, target)});
    // std.debug.print(glfw)
}

// 这是一个辅助函数，用于获取 em++ 的路径
fn emppPath(
    b: *std.Build,
    target: std.Build.ResolvedTarget,
) []const u8 {

    // em++ 和 emcc 在同一个目录下
    const emcc_path = @import("zemscripten").emccPath(b);
    return std.fs.path.join(b.allocator, &.{
        std.fs.path.dirname(emcc_path) orelse "",
        switch (target.result.os.tag) {
            .windows => "em++.bat",
            else => "em++",
        },
    }) catch unreachable;
}
// 这是编译 C++ 的核心函数
fn buildCpp(
    b: *std.Build,
    target: std.Build.ResolvedTarget,
    optimize: std.builtin.OptimizeMode,
    options: anytype,
) *std.Build.Step {
    // _ = target; // 在这个例子中我们不直接使用 Zig 的 target
    // const options = .{
    //     .backend = b.option(Backend, "backend", "Backend to build (default: no_backend)") orelse .no_backend,
    //     .shared = b.option(
    //         bool,
    //         "shared",
    //         "Bulid as a shared library",
    //     ) orelse false,
    //     .with_implot = b.option(
    //         bool,
    //         "with_implot",
    //         "Build with bundled implot source",
    //     ) orelse false,
    //     .with_gizmo = b.option(
    //         bool,
    //         "with_gizmo",
    //         "Build with bundled ImGuizmo tool",
    //     ) orelse false,
    //     .with_node_editor = b.option(
    //         bool,
    //         "with_node_editor",
    //         "Build with bundled ImGui node editor",
    //     ) orelse false,
    //     .with_te = b.option(
    //         bool,
    //         "with_te",
    //         "Build with bundled test engine support",
    //     ) orelse false,
    //     .with_freetype = b.option(
    //         bool,
    //         "with_freetype",
    //         "Build with system FreeType engine support",
    //     ) orelse false,
    //     .use_wchar32 = b.option(
    //         bool,
    //         "use_wchar32",
    //         "Extended unicode support",
    //     ) orelse false,
    //     .use_32bit_draw_idx = b.option(
    //         bool,
    //         "use_32bit_draw_idx",
    //         "Use 32-bit draw index",
    //     ) orelse false,
    //     .disable_thread_safety = b.option(
    //         bool,
    //         "disable_thread_safety",
    //         "Disable thread safety",
    //     ) orelse false,
    // };
    const cflags = &.{
        "-fno-sanitize=undefined",
        "-Wno-elaborated-enum-base",
        "-Wno-error=date-time",
        "-DLIBO_XIUGAI",
        // "-DEMSCRIPTEN_USE_PORT_CONTRIB_GLFW3",
        // "-DIMGUI_IMPL_OPENGL_ES3",
        "-DIMGUI_IMPL_OPENGL_LOADER_CUSTOM",
        // "-DIMGUI_IMPL_API=extern \"C\"",
        // -DIMGUI_IMPL_OPENGL_ES3
        if (options.use_32bit_draw_idx) "-DIMGUI_USE_32BIT_DRAW_INDEX" else "",
    };
    // -DIMGUI_IMPL_OPENGL_LOADER_CUSTOM
    // const objcflags = &.{
    //     "-Wno-deprecated",
    //     "-Wno-pedantic",
    //     "-Wno-availability",
    // };
    // 导入 zemscripten
    // const zemscripten = b.dependency("zemscripten", .{}).module("root");

    // 1. 关键：确保 Emscripten SDK 已被激活
    // 这是 zemscripten 提供的最有用的功能之一
    // const activate_step = zemscripten.activateEmsdkStep(b);
    const activate_step = @import("zemscripten").activateEmsdkStep(b);

    // 2. 创建一个系统命令来调用 em++
    var empp = b.addSystemCommand(&.{emppPath(b, target)});

    // 3. 让编译命令依赖于 SDK 激活步骤
    empp.step.dependOn(activate_step);
    if (b.lazyDependency("zglfw", .{})) |zglfw| {
        const path_str = zglfw.path("").getPath3(b, null);
        const full_path = b.pathResolve(&.{ path_str.root_dir.path orelse ".", path_str.sub_path });
        std.debug.print("{s}\n", .{full_path});

        empp.addArgs(&.{
            "-I",
            full_path,
        });

        std.debug.print("{s}\n", .{full_path});
    }
    empp.addArgs(&.{
        "-I",
        "./libs",
        "-I",
        "./libs/imgui",
        "-r",
    });
    empp.addArgs(cflags);
    // 4. 添加 C++ 源文件
    // 这里我们简单地列出文件，你也可以用代码扫描目录来添加
    empp.addFileArg(b.path("libs/imgui/imgui.cpp"));
    empp.addFileArg(b.path("libs/imgui/imgui_widgets.cpp"));
    empp.addFileArg(b.path("libs/imgui/imgui_tables.cpp"));
    empp.addFileArg(b.path("libs/imgui/imgui_draw.cpp"));
    empp.addFileArg(b.path("libs/imgui/imgui_demo.cpp"));
    empp.addFileArg(b.path("src/zgui.cpp"));

    empp.addFileArg(b.path("libs/imgui/backends/imgui_impl_glfw.cpp"));
    empp.addFileArg(b.path("libs/imgui/backends/imgui_impl_opengl3.cpp"));

    // imgui.addCSourceFiles(.{
    //     .files = &.{
    //         "libs/imgui/backends/imgui_impl_glfw.cpp",
    //         "libs/imgui/backends/imgui_impl_opengl3.cpp",
    //     },
    //     .flags = &(cflags.* ++ .{"-DIMGUI_IMPL_OPENGL_LOADER_CUSTOM"}),
    // });

    // 5. 添加编译参数
    // 设置优化级别
    switch (optimize) {
        // .Debug => empp.addArgs(&.{ "-O0", "-gsource-map" }),
        .Debug => empp.addArgs(&.{"-O0"}),
        .ReleaseSafe => empp.addArgs(&.{"-O2"}),
        .ReleaseFast => empp.addArgs(&.{"-O3"}),
        .ReleaseSmall => empp.addArgs(&.{"-Oz"}),
    }

    // 添加 Emscripten 特有的设置 (-s KEY=VALUE)
    empp.addArgs(&.{
        // "-c", //只编译不链接
        // "-r",
        "-s", "USE_GLFW=3", // 示例：如果你用到了 GLFW
        "-s", "USE_WEBGL2=1", // 示例：如果你用到了 WebGL2
        // "-s", "ALLOW_MEMORY_GROWTH=1", // 允许内存增长
        "-emit-llvm",
        // "-s",
        // "FULL_ES3=1", //"-s",
        // "STRICT=0", // "-s",
        // "GL_ENABLE_GET_PROC_ADDRESS=1", "-s",
        // "GL_EXPLICIT_UNIFORM_LOCATION=0",
        // "-s", "EXPORTED_RUNTIME_METHODS=[\"cwrap\"]", // 导出一些方法
        // "-o","imgui.bc",
    });

    // 6. 指定输出文件
    // em++ 会自动生成 .js 和 .wasm 文件
    const output_path = b.getInstallPath(.bin, "libimgui.a");
    empp.addArgs(&.{ "-o", output_path });

    return &empp.step;
}
